#ifdef SYPX_MEMCHECK
#include "mmgr.h"
#endif

#include "Engine.h"
#include "Base.h"
#include "Sprite.h"
#include "Texture.h"
#include "SpriteInstance.h"
#include "ResourceManager.h"

namespace SypX
{
	int Sprite::offset = 0;

	Sprite::Sprite():mi(0)
	{

	}
	Sprite* Sprite::loadSpriteFromFile(const String& filename, bool genColor)
	{
		FileInputStream fin;
		String temp, texName;
		UShort numActions = 0;
		Sprite::SpriteActions sa;

		Sprite* sp = static_cast<Sprite*>(ResourceManager::getSingleton()->checkResource(filename));
		if(sp)
		{
			return sp;
		}

		sp = new Sprite();

		String path = Engine::getFilePath(filename);
		fin.open( path.c_str());		//load sprite file
		sp->setFileName(filename);

		std::getline(fin, texName);		//read in texture filename
		fin>>numActions;				//read in number of actions	


		sp->tex = Texture::loadFromFile(texName);

		for(UByte i = 0; i < numActions; ++i)
		{
			std::getline(fin, temp);		//finish reading line
			std::getline(fin, sa.actionName);		//read in action name
			fin>>sa.numFrames;
			for(int k = 0; k < sa.numFrames; ++k)
			{
				float t;
				fin>>t;						//frame duration
				sa.frameDuration.push_back(t);
			}
			fin>>sa.btm;
			fin>>sa.cellHeight;
			fin>>sa.cellWidth;


			sp->actions.push_back(sa);
		}


		sp->mi = new MeshInstance();
		sp->mi->useMesh(sp);
		sp->mi->useTexture(sp->tex);

		sp->removeRef();//You should never do this, done here bcos its a dummy 
		sp->tex->removeRef();
		if(!genColor)
		{
			sp->stride = 20;
		}
		else
		{
			sp->stride = 32;
		}
		//initAsQuad( static_cast<float>(actions[0].cellWidth), static_cast<float>(actions[0].cellHeight) );	
		return sp;

	}	

	void Sprite::drawBufferedInstances()
	{
		if(data.size() > 0)
		{
			Engine::getSingleton()->getSingleton()->getRenderer()->drawMesh(mi);
			data.clear();
		}
	}

	void Sprite::setOffsetAngle(int off)
	{
		offset = off;
	}

	void Sprite::bufferInstance(SpriteInstance* si)
	{
		float btmN, cellW, cellH;
		UShort activeAction = si->getActiveAction();
		UShort activeFrame = si->getActiveFrame();
		short activeAngle = static_cast<short>(si->getActiveAngle()) + offset;
		if(activeAngle < 0)
		{
			activeAngle += 12;

		}
		if(activeAngle > 6)
		{
			//activeAngle = 0 - (12 - activeAngle);		//flip texture
			activeAngle -= 12;
		}

		SpriteActions& currAction = actions[activeAction];

		btmN = currAction.btm / static_cast<float>(tex->getHeight());
		cellW = currAction.cellWidth / static_cast<float>(tex->getWidth());
		cellH = currAction.cellHeight / static_cast<float>(tex->getHeight());
		//Half width/height
		float hw = currAction.cellWidth / 2.0f;
		float hh = currAction.cellHeight / 2.0f;

		float depth = si->getPositionRef().z;

		unsigned int oldsize = data.size();
		data.resize( data.size() +  stride/sizeof(float) * 6);//allocate sufficient memory for new instance(6 vertices per quad)

		FloatArray::iterator i = data.begin() + oldsize;

		const Vec4& siPos = si->getPositionRef();

		//top left 
		(*i) = -hw + siPos.x;
		++i;
		(*i) = hh  + siPos.y;
		++i;
		(*i) = depth;
		++i;			
		(*i) = activeAngle * cellW;
		++i;
		(*i) = btmN + (activeFrame + 1) * cellH;
		++i;

		//btm left
		(*i) = -hw + siPos.x;
		++i;
		(*i) = -hh + siPos.y;
		++i;
		(*i) = depth;
		++i;			
		(*i) = activeAngle * cellW;
		++i;
		(*i) = btmN + activeFrame * cellH;
		++i;


		//btm right
		(*i) = hw + siPos.x;
		++i;
		(*i) = -hh + siPos.y;
		++i;
		(*i) = depth;
		++i;			
		(*i) = (activeAngle + 1) * cellW;
		++i;
		(*i) = btmN + activeFrame * cellH;
		++i;

		//top right
		(*i) = hw + siPos.x;
		++i;
		(*i) = hh + siPos.y;
		++i;
		(*i) = depth;
		++i;			
		(*i) = (activeAngle + 1) * cellW;
		++i;
		(*i) = btmN + (activeFrame + 1) * cellH;
		++i;

		//top left 
		(*i) = -hw + siPos.x;
		++i;
		(*i) = hh + siPos.y;
		++i;
		(*i) = depth;
		++i;			
		(*i) = activeAngle * cellW;
		++i;
		(*i) = btmN + (activeFrame + 1) * cellH;
		++i;

		//btm right
		(*i) = hw + siPos.x;
		++i;
		(*i) = -hh + siPos.y;
		++i;
		(*i) = depth;
		++i;			
		(*i) = (activeAngle + 1) * cellW;
		++i;
		(*i) = btmN + activeFrame * cellH;
		++i;

		if(activeAngle < 0)		
		{//do invert
			activeAngle = 0 - activeAngle;//make it positive again
			//top left uv
			data[oldsize + 3] = (activeAngle + 1) * cellW;
			data[oldsize + 4] = btmN + (activeFrame + 1) * cellH;

			//btm left
			data[oldsize + 8] = (activeAngle + 1) * cellW;
			data[oldsize + 9] = btmN + activeFrame * cellH;

			//btm right
			data[oldsize + 13] = (activeAngle) * cellW;
			data[oldsize + 14] = btmN + activeFrame * cellH;

			//top right
			data[oldsize + 18] = (activeAngle) * cellW;
			data[oldsize + 19] = btmN + (activeFrame + 1) * cellH;

			//top left uv
			data[oldsize + 23] = (activeAngle + 1) * cellW;
			data[oldsize + 24] = btmN + (activeFrame + 1) * cellH;

			//btm right
			data[oldsize + 28] = (activeAngle) * cellW;
			data[oldsize + 29] = btmN + activeFrame * cellH;

		}

	}


	void Sprite::updateMesh(SpriteInstance* si)
	{		
		float btmN, cellW, cellH;
		UShort activeAction = si->getActiveAction();
		UShort activeFrame = si->getActiveFrame();
		short activeAngle = si->getActiveAngle();
		if(activeAngle > 6)
		{
			activeAngle = 0 - (12 - activeAngle);		//flip texture
		}

		SpriteActions& currAction = actions[activeAction];

		btmN = currAction.btm / static_cast<float>(tex->getHeight());
		cellW = currAction.cellWidth / static_cast<float>(tex->getWidth());
		cellH = currAction.cellHeight / static_cast<float>(tex->getHeight());

		if(activeAngle >= 0)
		{
			//top left uv
			data[3] = activeAngle * cellW;
			data[4] = btmN + (activeFrame + 1) * cellH;

			//btm left
			data[8] = activeAngle * cellW;
			data[9] = btmN + activeFrame * cellH;

			//btm right
			data[13] = (activeAngle + 1) * cellW;
			data[14] = btmN + activeFrame * cellH;

			//top right
			data[18] = (activeAngle + 1) * cellW;
			data[19] = btmN + (activeFrame + 1) * cellH;

			//top left uv
			data[23] = activeAngle * cellW;
			data[24] = btmN + (activeFrame + 1) * cellH;

			//btm right
			data[28] = (activeAngle + 1) * cellW;
			data[29] = btmN + activeFrame * cellH;
		}
		else
		{
			activeAngle = 0 - activeAngle;//make it positive again
			//top left uv
			data[3] = (activeAngle + 1) * cellW;
			data[4] = btmN + (activeFrame + 1) * cellH;

			//btm left
			data[8] = (activeAngle + 1) * cellW;
			data[9] = btmN + activeFrame * cellH;

			//btm right
			data[13] = (activeAngle) * cellW;
			data[14] = btmN + activeFrame * cellH;

			//top right
			data[18] = (activeAngle) * cellW;
			data[19] = btmN + (activeFrame + 1) * cellH;

			//top left uv
			data[23] = (activeAngle + 1) * cellW;
			data[24] = btmN + (activeFrame + 1) * cellH;

			//btm right
			data[28] = (activeAngle) * cellW;
			data[29] = btmN + activeFrame * cellH;

		}

	}	


	Texture* Sprite::getTexture()
	{
		return tex;
	}

	Sprite::~Sprite(void)
	{
		if(mi)
		{
			//Add back ref to prevent count from dropping to negative when deleting dummy MeshInstance
			addRef();
			tex->addRef();
			delete mi;
		}




	}

}